/**
 * @function 日功
 * @encode utf-8
 * @copyright (C) lijun
 * @file calendar.js
 * @author lijun
 * @version 1.0
 * @date 2010-3-6
 */

/**
 * 日历控件构造函数
 */
XLib.Calendar = function(){
    this.PREFIX = "XLIB_CALENDAR_";
    this.SECURE_PAGE = "MSIE" == UA.Browser.ie > 0 ? "javascript:''" : "about:blank";
    this.WIDTH = 175;
    this.HEIGHT = 200;
    this.WEEKDAYS = {
        "Sunday" : {en_abbr:"Sun.", abbr:"日", full:"星期日"},
		"Monday" : {en_abbr:"Mon.", abbr:"一", full:"星期一"},
		"Tuesday" : {en_abbr:"Tues.", abbr:"二", full:"星期二"},
		"Wednesday" : {en_abbr:"Wed.", abbr:"三", full:"星期三"},
		"Thursday" : {en_abbr:"Thur.", abbr:"四", full:"星期四"},
		"Friday" : {en_abbr:"Fri.", abbr:"五", full:"星期五"},
		"Saturday" : {en_abbr:"Sat.", abbr:"六", full:"星期六"}
    };
    this.MONTHS = [
        {en:"january", text:"一", value:"01"},
		{en:"february", text:"二", value:"02"},
		{en:"march", text:"三", value:"03"},
		{en:"april", text:"四", value:"04"},
		{en:"may", text:"五", value:"05"},
		{en:"june", text:"六", value:"06"},
		{en:"july", text:"七", value:"07"},
		{en:"august", text:"八", value:"08"},
		{en:"september", text:"九", value:"09"},
		{en:"october", text:"十", value:"10"},
		{en:"november", text:"十一", value:"11"},
		{en:"december", text:"十二", value:"12"}
    ];
    this.config = {
        id : 0,
        size : 1,
        rows : 1,
        cols : 1,
        showToday : false,
        namespace : 'cal',
        range : {start:null, end:null, disabled:false},
        bind : [], //{ref[],input,handler,args}
        offsetX : 0,
        offsetY : 0,
        bindNext : true,
        format : '%y-%M-%d'
    };
    this.def_date = new Date();
    this.previous_list = null;
    this.isMultiple = false;
    this.index = 0;
};

/**
 * 原型扩展
 */
XLib.Calendar.prototype = {
    /**
     * 初始化
     * @param cfg {id,size,rows,cols,showToday,namespace,range,bin,offsetX,offsetY,bindNext,format}
     */
    init : function(cfg)
    {
        var conf = cfg || null;
        for(var key in conf)
        {
            if(conf.hasOwnProperty(key))
            {
                this.config[key] = conf[key];
            }
        }
        this.isMultiple = (this.config["size"] > 1);
        this.setCSS();
        this.bindCalendar();
    },
    /**
     * 设置CSS
     */
    setCSS : function(){
        var cssTexts = [
            '.cal-panel{font:normal normal normal 12px/16px simsun; overflow:hidden; background:#fff;}',
            '.cal-panel .cal-calendar-p{width:175px; height:auto; position:relative; float:left;}',
            '.cal-panel .cal-calendar{border:#9DB0BC solid 1px; width:175px; height:auto; border-collapse:separate; *border-collapse:collapse;}',
            '.cal-panel .cal-calendar td{padding:0px; margin:0px; border:none;}',
            '.cal-panel .cal-head, .cal-panel .cal-body, .cal-panel .cal-foot{width:100%;}',
            '.cal-panel .cal-head td{border-bottom:#9DB0BC solid 1px; height:28px; vertical-align:middle; text-align:center;}',
            '.cal-panel .cal-head em.cal-btn-month{display:-moz-stack-inline; display:inline-block; zoom:1; *display:inline; padding:0px; margin:0px; width:0px; height:0px; overflow:hidden; border-top:solid 5px #fff; border-bottom:solid 5px #fff; cursor:pointer; vertical-align:middle;}',
            '.cal-panel .cal-head em.cal-btn-pre-month{border-right:solid 5px #7c9db1;border-left:none; margin-right:8px;}',
            '.cal-panel .cal-head em.cal-btn-next-month{border-right:none; border-left:solid 5px #7c9db1; margin-left:8px;}',
            '.cal-panel .cal-head span{display:-moz-stack-inline; display:inline-block; zoom:1; *display:inline; width:56px; height:22px; _height:12px; line-height:26px; margin:0px 3px; _padding:2px 0px 0px 0px; cursor:pointer; vertical-align:middle; overflow:hidden;}',
            '.cal-panel .cal-head code{display:inline; margin:0px 2px 0px 0px;}',
            '.cal-panel .cal-head em.cal-down{display:-moz-stack-inline; display:inline-block; zoom:1; *display:inline; margin:0px 0px 0px 2px; width:0px; height:0px; border-left:solid 3px #fff; border-right:solid 3px #fff; border-top:solid 3px #7c9db1;border-bottom:none; cursor:pointer; vertical-align:2px; overflow:hidden;}',
            '.cal-panel .cal-head div.cal-year-list{position:absolute; left:37px; top:22px; border:1px solid #9DB0BC; background:#f8f8f8; width:48px; height:146px;}',
            '.cal-panel .cal-head div.cal-pre-date{width:0px; height:0px; border-left:solid 4px #f8f8f8; border-right:solid 4px #f8f8f8; border-bottom:solid 4px #7c9db1; margin:3px auto; cursor:pointer; overflow:hidden;}',
            '.cal-panel .cal-head div.cal-next-date{width:0px; height:0px; border-left:solid 3px #f8f8f8; border-right:solid 3px #f8f8f8; border-top:solid 3px #7c9db1; margin:3px auto; cursor:pointer; overflow:hidden;}',
            '.cal-panel .cal-head div.cal-list-year{height:16px; line-height:16px; overflow:hidden; cursor:pointer; color:#666;}',
            '.cal-panel .cal-head div.cal-list-year-hovr{height:16px; line-height:16px; overflow:hidden; cursor:pointer; background:#07679C; color:#fff;}',
            '.cal-panel .cal-head div.cal-month-list{position:absolute; left:100px; top:22px; border:1px solid #9DB0BC; background:#f8f8f8; width:48px; height:146px;}',
            '.cal-panel .cal-head div.cal-list-month{height:16px; line-height:16px; overflow:hidden; cursor:pointer; color:#666;}',
            '.cal-panel .cal-head div.cal-list-month-hovr{height:16px; line-height:16px; overflow:hidden; cursor:pointer; background:#07679C; color:#fff;}',
            '.cal-panel .cal-week td{border-bottom:#9DB0BC solid 1px; width:25px; height:20px; text-align:center; color:#333;}',
            '.cal-panel .cal-date td{width:25px; height:20px; text-align:center; color:#07679C; cursor:pointer;}',
            '.cal-panel .cal-date td.cal-null{cursor:default;}',
            '.cal-panel .cal-date td.cal-current{background:#043C59; color:#fff;}',
            '.cal-panel .cal-date td.cal-disabled{color:#999; cursor:default;}',
            '.cal-panel .cal-date td.cal-disabled-current{background:#043C59; color:#fff; cursor:default;}',
            '.cal-panel .cal-date td.cal-not-in-range{color:#999;}',
            '.cal-panel .cal-date td.cal-mover{background:#07679C; color:#fff;}',
            '.cal-panel .cal-date td.cal-def-date{background:#07679C; color:#fff;}',
            '.cal-panel .cal-foot td{border-top:#9DB0BC solid 1px; height:25px; vertical-align:middle; text-align:center;}',
            '.cal-panel .cal-foot button{border:none; background:#fff; font:normal normal normal 12px/16px simsun; color:#333; cursor:pointer;}'
        ];
        XLib.CSS.dynamicStyle(cssTexts, "xlib_calander_css");
    },
    /**
     * 获取相对位置
     * @param ref 参考节点
     * @return {x,y}
     */
    getPosition : function(ref)
    {
        return XLib.getPosition(ref);
    },
    /**
     * 创建iframe
     */
    createIframe : function()
    {
        var ifr = XLib.DOM.$C("iframe");
        var cfg = this.config;
        var _id = this.PREFIX + "iframe_" + cfg.id;
        var _url = this.SECURE_PAGE;
        var attrs = {frameBorder:0, vSpacing:0, hSpacing:0, marginWidth:0, marginHeight:0, scrolling:'no', src:_url, id:_id};
        var _width = cfg.cols * this.WIDTH;
        var _height = cfg.rows * this.HEIGHT;
        for(var attr in attrs)
        {
            if(attrs.hasOwnProperty(attr))
            {
                ifr.setAttribute(attr, attrs[attr]);
            }
        }
        ifr.style.cssText = "width:" + _width + "px; height:" + _height + "px; position:absolute; z-index:-1; left:0px; top:0px;";
        return ifr;
    },
    /**
     * 创建面板
     * @param refNode 参考节点
     * @param offsetX 偏移量x
     * @param offsetY 偏移量y
     * @return {panel, calendar}
     */
    createPanel : function(refNode, offsetX, offsetY){
        var cfg = this.config;
        var _id = this.PREFIX + "panel_" + cfg.id;
        var _calId = this.PREFIX + "calendar_" + cfg.id;
        var _width = cfg.cols * this.WIDTH;
        var _height = cfg.rows * this.HEIGHT;
        var panel = XLib.DOM.$E(_id);
        var ifr = null;
        var cal = null;
        var pos = null;
        var _this = this;
        pos = this.getPosition(refNode);
        if(null == panel)
        {
            ifr = this.createIframe();
            cal = XLib.DOM.$C("div");
            cal.setAttribute("id", _calId);
            panel = XLib.DOM.$C("div");
            panel.setAttribute("id", _id);
            panel.className = "cal-panel";
            XLib.DOM.$A(ifr, panel);
            XLib.DOM.$A(cal, panel);
            XLib.DOM.$A(panel);
            XLib.Event.addEventListener(panel, "mouseup", function()
            {
                XLib.Event.preventDefault();
                XLib.Event.stopPropagation();
            }, [], false);
            cal.onmouseup = function(event)
            {
                var e = event || window.event;
                var obj = e.target || e.srcElement;
                var tagName = (obj.tagName).toLowerCase();
                var cls = (obj.className).toLowerCase();
                if("span" != tagName || "code" != tagName || "cal-down" != cls)
                {
                    _this.hidePreviousList();
                }
            };
        }
        panel.style.cssText = "position:absolute; left:" + (pos.x + offsetX) + "px; top:" + (pos.y + offsetY) + "px; z-index:4000; width:" + _width + "px; height:" + _height + "px; display:none;";
        this.clearHistoryCalendar(_calId);
        return {"panel":panel, "calendar":cal};
    },
    /**
     * 清除日历
     * @param calId 日历ID
     */
    clearHistoryCalendar : function(calId)
    {
        var cal = XLib.DOM.$E(calId);
        cal.innerHTML = "";
    },
    /**
     * 创建表格
     * @param row 行
     * @param col 列
     * @return {t, b, p}
     */
    createTable : function(row, col)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "table_" + cfg.id + "_" + row + "_" + col;
        var divId = this.PREFIX + "div_" + cfg.id + "_" + row + "_" + col;
        var div = XLib.DOM.$C("div");
        var table = XLib.DOM.$C("table");
        var tbody = XLib.DOM.$C("tbody");
        var attrs = {id:_id, border:0, cellpadding:0, cellspacing:0};
        div.className = "cal-calendar-p";
        table.className = "cal-calendar";
        tbody.className = "cal-body";
        div.setAttribute("id", divId);
        for(var attr in attrs)
        {
            if(attrs.hasOwnProperty(attr))
            {
                table.setAttribute(attr, attrs[attr]);
            }
        }
        XLib.DOM.$A(tbody, table);
        XLib.DOM.$A(table, div);
        return {t:table, b:tbody, p:div};
    },
    /**
     * 改变日历
     * @param row 行
     * @param col 列
     * @param format 日期格式
     * @param interval 周期
     * @param offset 偏移值
     */
    changeCalendar : function(row, col, format, interval, offset){
        var cfg = this.config;
        var _id = this.PREFIX + "panel_" + cfg.id;
        var month_id = this.PREFIX + "month_" + cfg.id + "_" + row + "_" + col;
        var year_id = this.PREFIX + "year_" + cfg.id + "_" + row + "_" + col;
        var panel = XLib.DOM.$E(_id);
        var month = XLib.DOM.$E(month_id);
        var year = XLib.DOM.$E(year_id);
        var date = new Date()
        var dtStr = year.innerHTML + "-" + month.getAttribute("month") + "-01";
        date = date.parseDate(dtStr, format);
        if(offset != 0)
        {
            date = date.dateAdd(interval, offset);
        }
        this.clearHistoryCalendar(this.PREFIX + "calendar_" + cfg.id);
        this.createCalendar(panel, date, format);
        panel = null; year = null; month = null; date = null;
    },
    /**
     * 隐藏前一个列表
     */
    hidePreviousList : function()
    {
        if(null != this.previous_list)
        {
            this.hideMonthList(this.previous_list.replace("year", "month"));
            this.hideYearList(this.previous_list.replace("month", "year"));
            this.previous_list = null;
        }
    },
    /**
     * 获取月份列表
     * @param iMonth 月份
     * @param row 行
     * @param col 列
     * @param format 日期格式
     * @return str;
     */
    getMonthList : function(iMonth, row, col, format)
    {
        var cfg = this.config;
        var months = this.MONTHS;
        var size = months.length;
        var str = "";
        var item = null;
        var start = iMonth;
        var end = start + 8;
        var str = '<div class="cal-pre-date" onclick="'+cfg.namespace+'.turnMonth(0, \''+row+'\', \''+col+'\', \''+format+'\')"></div>';
        for(var i = start; i < size && i < end; i++)
        {
            item = months[i];
            str += '<div class="cal-list-month" onmouseover="this.className=\'cal-list-month-hovr\'" onmouseout="this.className=\'cal-list-month\'" onclick="'+cfg.namespace+'.setCheckedMonth(\''+item.value+'\', \''+item.text+'\', \''+row+'\', \''+col+'\', \''+format+'\')">'+item.text+'月</div>';
        }
        str += '<div class="cal-next-date" onclick="'+cfg.namespace+'.turnMonth(4, \''+row+'\', \''+col+'\', \''+format+'\')"></div>';
        return str;
    },
    /**
     * 月份列表翻页
     * @param iMonth 月份
     * @param row 行
     * @param col 列
     * @param format 日期格式
     */
    turnMonth : function(iMonth, row, col, format)
    {
        var cfg = this.config;
        var month_id = this.PREFIX + "month_" + cfg.id + "_" + row + "_" + col;
        var month_list_id = this.PREFIX + "month_list_" + cfg.id + "_" + row + "_" + col;
        var list = XLib.DOM.$E(month_list_id);
        list.innerHTML = this.getMonthList(iMonth, row, col, format);
        list = null;
    },
    /**
     * 设置月份
     * @param sMonth 月份
     * @param sText 月份文本
     * @param row 行
     * @param col 列
     * @param format 日期格式
     */
    setCheckedMonth : function(sMonth, sText, row, col, format)
    {
        var cfg = this.config;
        var month_id = this.PREFIX + "month_" + cfg.id + "_" + row + "_" + col;
        var month_list_id = this.PREFIX + "month_list_" + cfg.id + "_" + row + "_" + col;
        var month = XLib.DOM.$E(month_id);
        var list = XLib.DOM.$E(month_list_id);
        month.innerHTML = sText;
        month.setAttribute("month", sMonth);
        this.changeCalendar(row, col, format, 'y', 0);
        list.style.display = "none";
        month = null; list = null;
    },
    /**
     * 阻止冒泡
     * @param obj 对象
     */
    stopEventBubble : function(obj)
    {
        XLib.Event.addEventListener(obj, "mouseup", function()
        {
            XLib.Event.preventDefault();
            XLib.Event.stopPropagation();
        }, [], false);
    },
    /**
     * 显示月份列表
     * @param obj 当前节点对象
     * @param row 行
     * @param col 列
     * @param format 日期格式
     * @param monthId 月份节点ID
     * @param monthListId 列表ID
     */
    showMonthList : function(obj, row, col, format, monthId, monthListId)
    {
        var list = XLib.DOM.$E(monthListId);
        list.innerHTML = this.getMonthList(0, row, col, format);
        list.style.display = "block";
        list = null;
        this.hidePreviousList();
        this.hideYearList(monthListId.replace("month", "year"));
        this.previous_list = monthListId;
    },
    /**
     * 隐藏月份列表
     * @param monthListId 列表ID
     */
    hideMonthList : function(monthListId)
    {
        var list = XLib.DOM.$E(monthListId);
        list.style.display = "none";
    },
    /**
     * 获取月份列表
     * @param iYear 年
     * @param row 行
     * @param col 列
     * @param format 日期格式
     * @return str;
     */
    getYearList : function(iYear, row, col, format)
    {
        var cfg = this.config;
        var end = iYear + 8;
        var str = '<div class="cal-pre-date" onclick="'+cfg.namespace+'.turnYear('+(iYear - 7)+', \''+row+'\', \''+col+'\', \''+format+'\')"></div>';
        for(var i = iYear; i < end; i++)
        {
            str += '<div class="cal-list-year" onmouseover="this.className=\'cal-list-year-hovr\'" onmouseout="this.className=\'cal-list-year\'" onclick="'+cfg.namespace+'.setCheckedYear('+i+', \''+row+'\', \''+col+'\', \''+format+'\')">'+i+'年</div>';
        }
        str += '<div class="cal-next-date" onclick="'+cfg.namespace+'.turnYear('+end+', \''+row+'\', \''+col+'\', \''+format+'\')"></div>';
        return str;
    },
    /**
     * 设置年份
     * @param iYear 年份
     * @param row 行
     * @param col 列
     * @param format 日期格式
     */
    setCheckedYear : function(iYear, row, col, format)
    {
        var cfg = this.config;
        var year_id = this.PREFIX + "year_" + cfg.id + "_" + row + "_" + col;
        var year_list_id = this.PREFIX + "year_list_" + cfg.id + "_" + row + "_" + col;
        var year = XLib.DOM.$E(year_id);
        var list = XLib.DOM.$E(year_list_id);
        year.innerHTML = iYear;
        this.changeCalendar(row, col, format, 'y', 0);
        list.style.display = "none";
        year = null; list = null;
    },
    /**
     * 年份列表翻页
     * @param iYear 年份
     * @param row 行
     * @param col 列
     * @param format 日期格式
     */
    turnYear : function(iYear, row, col, format)
    {
        if(iYear < 1900){iYear = 1900;}
        if(iYear > 2093){iYear = 2093;}
        var cfg = this.config;
        var year_id = this.PREFIX + "year_" + cfg.id + "_" + row + "_" + col;
        var year_list_id = this.PREFIX + "year_list_" + cfg.id + "_" + row + "_" + col;
        var list = XLib.DOM.$E(year_list_id);
        list.innerHTML = this.getYearList(iYear, row, col, format);
        list = null;
    },
    /**
     * 显示月份列表
     * @param obj 当前节点对象
     * @param row 行
     * @param col 列
     * @param format 日期格式
     * @param yearId 年份节点ID
     * @param yearListId 列表ID
     */
    showYearList : function(obj, row, col, format, yearId, yearListId)//年份列表
    {
        var year = XLib.DOM.$E(yearId);
        var list = XLib.DOM.$E(yearListId);
        var iYear = year.innerHTML * 1;
        list.innerHTML = this.getYearList(iYear, row, col, format);
        list.style.display = "block";
        year = null; list = null;
        this.hidePreviousList();
        this.hideMonthList(yearListId.replace("year", "month"));
        this.previous_list = yearListId;
    },
    /**
     * 隐藏年份列表
     * @param yearListId 列表ID
     */
    hideYearList : function(yearListId)
    {
        var list = XLib.DOM.$E(yearListId);
        list.style.display = "none";
    },
    /**
     * 创建表头
     * @param table 表格对象
     * @param row 行
     * @param col 列
     * @param format 日期格式
     */
    createHead : function(table, row, col, format)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "head_" + cfg.id + "_" + row + "_" + col;
        var month_id = this.PREFIX + "month_" + cfg.id + "_" + row + "_" + col;
        var year_id = this.PREFIX + "year_" + cfg.id + "_" + row + "_" + col;
        var month_list_id = this.PREFIX + "month_list_" + cfg.id + "_" + row + "_" + col;
        var year_list_id = this.PREFIX + "year_list_" + cfg.id + "_" + row + "_" + col;
        var thead = table.createTHead();
        var tr = thead.insertRow(-1);
        var td = tr.insertCell(-1);
        var pre = (0 === row + col) ? '<em class="cal-btn-month cal-btn-pre-month" onclick="'+cfg.namespace+'.changeCalendar(\''+row+'\', \''+col+'\', \''+format+'\', \'n\', ' + (-1 * cfg.size) + ')"></em>' : '';
        var next = (cfg.size == (row + 1) * (col + 1)) ? '<em class="cal-btn-month cal-btn-next-month" onclick="'+cfg.namespace+'.changeCalendar(\''+row+'\', \''+col+'\', \''+format+'\', \'n\', 1)"></em>' : '';
        thead.setAttribute("id", _id);
        thead.className = "cal-head";
        td.colSpan = 7;
        td.innerHTML = pre + '<span onclick="'+cfg.namespace+'.showYearList(this, \''+row+'\', \''+col+'\', \''+format+'\', \''+year_id+'\', \''+year_list_id+'\')"><code id="'+year_id+'"></code>年<em class="cal-down"></em></span><span onclick="'+cfg.namespace+'.showMonthList(this, \''+row+'\', \''+col+'\', \''+format+'\', \''+month_id+'\', \''+month_list_id+'\')"><code id="'+month_id+'"></code>月<em class="cal-down"></em></span>' + next + '<div onmouseup="'+cfg.namespace+'.stopEventBubble(this)" id="'+year_list_id+'" class="cal-year-list" style="display:none;"></div><div onmouseup="'+cfg.namespace+'.stopEventBubble(this)" id="'+month_list_id+'" class="cal-month-list" style="display:none;"></div>';
        table = null; thead = null; tr = null; td = null;
    },
    /**
     * 创建表尾
     * @param table 表格对象
     * @param row 行
     * @param col 列
     */
    createFoot : function(table, row, col)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "head_" + cfg.id + "_" + row + "_" + col;
        var tfoot = table.createTFoot();
        var tr = tfoot.insertRow(-1);
        var td = tr.insertCell(-1);
        tfoot.setAttribute("id", _id);
        tfoot.className = "cal-foot";
        td.colSpan = 7;
        td.innerHTML = '<button type="button" onclick="'+cfg.namespace+'.clickEvent()">'+(new Date().format('%y-%M-%d, %w'))+'</button>';
        table = null; tfoot = null; tr = null; td = null;
    },
    /**
     * 设置当前日期
     * @param date 日期
     * @param row 行
     * @param col 列
     */
    setCurrentDate : function(date, row, col)
    {
        var cfg = this.config;
        var month_id = this.PREFIX + "month_" + cfg.id + "_" + row + "_" + col;
        var year_id = this.PREFIX + "year_" + cfg.id + "_" + row + "_" + col;
        var month = XLib.DOM.$E(month_id);
        var year = XLib.DOM.$E(year_id);
        month.innerHTML = this.MONTHS[date.getMonth()].text;
        month.setAttribute("month", this.MONTHS[date.getMonth()].value);
        year.innerHTML = date.getFullYear();
    },
    /**
     * 创建表体
     * @param table 表格对象
     * @param row 行
     * @param col 列
     * @param date 日期
     */
    createBody : function(table, row, col, date)
    {
        var currentDate = new Date(date.getFullYear(), date.getMonth(), 1);
        var firstDay = currentDate.getDay();
        var leapYear = date.leapYear();
        var monthDays = leapYear.monthDays;
        for(var i = 0; i < 7; i++)
        {
            if(0 == i)
            {
                this.createWeekDays(table, row, col, i);
            }
            else
            {
                this.createDate(table, row, col, currentDate, date, i, firstDay, monthDays);
            }
        }
    },
    /**
     * 创建星期
     * @param table 表格对象
     * @param row 行
     * @param col 列
     * @param i 索引
     */
    createWeekDays : function(table, row, col, i)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "tr_weekdays_" + cfg.id + "_" + row + "_" + col + "_" + i;
        var weekDays = this.WEEKDAYS;
        var tr = table.insertRow(-1);
        var td = null;
        var j = 0;
        tr.className = "cal-week";
        tr.setAttribute("id", _id);
        for(var key in weekDays)
        {
            if(weekDays.hasOwnProperty(key))
            {
                _id = this.PREFIX + "td_weekdays_" + cfg.id + "_" + row + "_" + col + "_" + i + "_" + j;
                td = tr.insertCell(-1);
                td.innerHTML = weekDays[key]["abbr"];
                td.setAttribute("id", _id);
                j++;
            }
        }
        table = null; tr = null; td = null;
    },
    /**
     * 创建日期
     * @param table 表格对象
     * @param row 行
     * @param col 列
     * @param currentDate 当前日期
     * @param date 初始日期
     * @param i 索引
     * @param firstDay 一周的第一天
     * @param monthDays 一个月的天数
     */
    createDate : function(table, row, col, currentDate, date, i, firstDay, monthDays)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "tr_date_" + cfg.id + "_" + row + "_" + col + "_" + i;
        var tr = table.insertRow(-1);
        tr.className = "cal-date";
        tr.setAttribute("id", _id);
        for(var j = 0; j < 7; j++)
        {
            this.createDay(tr, row, col, currentDate, date, i, j, firstDay, monthDays);
        }
    },
    /**
     * 日期是否在指定的范围内
     * @param date 日期
     */
    inRange : function(date){
        var cfg = this.config;
        var ref = date.format("%y%M%d") * 1;
        var start = cfg.range.start ? (new Date().parseDate(cfg.range.start, "%y-%M-%d").format("%y%M%d")) * 1 : 0;
        var end = cfg.range.end ? (new Date().parseDate(cfg.range.end, "%y-%M-%d").format("%y%M%d")) * 1 : 99999999;
        var flag = false;
        if(ref >= start && ref <= end)
        {
            flag = true;
        }
        return flag;
    },
    /**
     * 创建日期
     * @param tr 表格行对象
     * @param row 行
     * @param col 列
     * @param currentDate 当前日期
     * @param date 初始日期
     * @param i 行索引
     * @param j 列索引
     * @param firstDay 一周的第一天
     * @param monthDays 一个月的天数
     */
    createDay : function(tr, row, col, currentDate, date, i, j, firstDay, monthDays)
    {
        var cfg = this.config;
        var _id = this.PREFIX + "td_date_" + cfg.id + "_" + row + "_" + col + "_" + i + "_" + j;
        var dis = cfg.range.disabled;
        var inc = false;
        var td = tr.insertCell(-1);
        var index = (i - 1) * 7 + j;
        var d2 = new Date();
        var d = currentDate.getDate();
        td.innerHTML = "&nbsp;";
        if(index >= firstDay && d <= monthDays && date.getMonth() == currentDate.getMonth())
        {
            td.innerHTML = d;
            inc = this.inRange(currentDate);
            if(!inc)
            {
                td.className = "cal-disabled";
            }
            if(!dis || inc)
            {
                this.bindClickEvent(td, new Date(currentDate.getTime()));
                this.bindMouseEvent(td);
                if(!inc)
                {
                    td.className = "cal-not-in-range";
                }
            }
            if(currentDate.format("%y%M%d") == d2.format("%y%M%d"))
            {
                td.className = inc ? "cal-current" : (dis ? "cal-disabled-current" : "cal-current");
            }
            if(currentDate.format("%y%M%d") == this.def_date.format("%y%M%d"))
            {
                td.className =  inc ? "cal-def-date" : (dis ? "cal-disabled-current cal-def-date" : "cal-def-date");
            }
            currentDate.dateAdd("d", 1);
        }
        else
        {
            td.className = "cal-null";
        }
    },
    /**
     * 点击事件
     * @param currentDate 当前日期
     */
    clickEvent : function(currentDate)
    {
        var cfg = this.config;
        var next = null;
        var list = cfg.bind || [];
        var size = list.length - 1;
        var index = this.index + 1;
        var item = list[this.index];
        next = size >= index ? list[index] : null;
        currentDate = currentDate || new Date();
        if(item && null != item.handler)
        {
            item.args.unshift(currentDate);
            item.handler.apply(null, item.args);
            item.args.shift();
        }
        this.hide();
        if(cfg.bindNext && null != next)
        {
            XLib.Event.dispatchEvent(next.ref, "click", null, null);
        }
    },
    /**
     * 绑定点击事件
     * @param td 表格单元格对象
     * @param currentDate 当前日期
     */
    bindClickEvent : function(td, currentDate){
        var cfg = this.config;
        var _this = this;
        td.onclick = function()
        {
            _this.clickEvent(currentDate);
        }
    },
    /**
     * 绑定鼠标事件
     * @param td 表格单元格对象
     */
    bindMouseEvent : function(td){
        td.onmouseover = function()
        {
            var cls = this.className;
            cls = cls.replace(/[\s ]*cal\-mover[\s ]*/, "");
            this.className = cls + " cal-mover";
        }
        td.onmouseout = function()
        {
            var cls = this.className;
            cls = cls.replace(/[\s ]*cal\-mover[\s ]*/, "");
            this.className = cls;
        }
    },
    /**
     * 创建日历
     * @param panel 面板
     * @param date 初始日期
     * @param format 日期格式
     */
    createCalendar : function(panel, date, format){
        var cfg = this.config;
        var table = null;
        var rows = cfg.rows;
        var cols = cfg.cols;
        var calId = this.PREFIX + "calendar_" + cfg.id;
        var cal = XLib.DOM.$E(calId);
        for(var row = 0; row < rows; row++)
        {
            for(var col = 0; col < cols; col++)
            {
                table = this.createTable(row, col);
                this.createHead(table.t, row, col, format);
                this.createBody(table.b, row, col, date);
                if(true === cfg.showToday)
                {
                    this.createFoot(table.t, row, col);
                }
                else
                {
                    panel.style.height = rows * (this.HEIGHT - 25);
                }
                XLib.DOM.$A(table.p, cal);
                this.setCurrentDate(date, row, col);
                date.setDate(1);
                date = date.dateAdd("n", 1);
            }
        }
        panel.style.display = "block";
        XLib.Event.addEventListener(document, "mouseup", function()
        {
            panel.style.display = "none";
            XLib.Event.removeEventListener(document, "mouseup", arguments.callee, [], false);
        }, [], false);
    },
    /**
     * 日期格式兼容
     * @param strDate 日期串
     * @param format 日期格式
     */
    compatible : function(strDate, format)
    {
        var fmts = [
            "%y%M%d", "%y-%M-%d", "%y.%M.%d", "%y年%M月%d日", "%y年%M月%d",
            "%M%d%y", "%M-%d-%y", "%M.%d.%y", "%M月%d日%y年", "%M月%d日%y",
            "%d%M%y", "%d-%M-%y", "%d.%M.%y", "%d日%M月%y年", "%d日%M月%y",
            "%M/%d, %w", "%d/%M, %w", "%M/%d, %W", "%d/%M, %W",
            "%M/%d, %a", "%d/%M, %a", "%M/%d, %A", "%d/%M, %A"
        ];
        var size = fmts.length;
        var valid = null;
        var date = new Date();
        var str = strDate;
        valid =  date.validDate(strDate, format);
        if(!valid.isValid)
        {
            for(var i = 0; i < size; i++)
            {
                valid = date.validDate(strDate, fmts[i]);
                if(valid.isValid)
                {
                    date = valid.date;
                    break;
                }
            }
        }
        else
        {
            date = valid.date;
        }
        str = date.format(format);
        return str;
    },
    /**
     * 绑定控件
     */
    bindCalendar : function()
    {
        var list = this.config.bind || [];
        var size = list.length;
        var o = null;
        var item = null;
        for(var i = 0; i < size; i++)
        {
            item = list[i];
            if(item.ref instanceof Array)
            {
                var rSize = item.ref.length;
                for(var j = 0; j < size; j++)
                {
                    o = XLib.DOM.$E(item.ref[j]);
                    if(null != o)
                    {
                        this.setBindEvent(o, item, i);
                    }
                }
            }
            else
            {
                o = XLib.DOM.$E(item.ref);
                if(null != o)
                {
                    this.setBindEvent(o, item, i);
                }
            }
        }
    },
    /**
     * 设置绑定事件
     * @param o 参考节点
     * @param item 绑定的参数
     * @param i 索引
     */
    setBindEvent : function(o, item, i)
    {
        var _this = this;
        var fmt = this.config.format || "%y-%M-%d";
        XLib.Event.addEventListener(o, "click", function(index){
            _this.show(item.input, _this.config.offsetX, _this.config.offsetY, fmt, index);
        }, [i], false);
    },
    /**
     * 显示日历
     * @param inputId 输入框ID
     * @param offsetX 偏移值x
     * @param offsetY 偏移值y
     * @param format 日期格式
     * @param index 控件绑定索引
     */
    show : function(inputId, offsetX, offsetY, format, index)
    {
        this.index = index;
        var refNode = XLib.DOM.$E(inputId);
        var panel = this.createPanel(refNode, offsetX, offsetY);
        var def = XLib.DOM.$E(inputId);
        var defDate = null != def ? (def.value).bothTrim() : "";
        var date = new Date();
        var fmt = (format || "%y-%M-%d");
        defDate = this.compatible(defDate, fmt);
        date = date.parseDate(defDate, fmt);
        this.def_date = new Date().parseDate(defDate, fmt);
        this.createCalendar(panel.panel, date, fmt);
    },
    /**
     * 隐藏日历
     */
    hide : function()
    {
        var cfg = this.config;
        var _id = this.PREFIX + "panel_" + cfg.id;
        var panel = XLib.DOM.$E(_id);
        panel.style.display = "none";
        panel = null;
    }
};